#!/bin/sh

export E2E_DISABLE_RESOURCE_REQUIREMENTS="${E2E_DISABLE_RESOURCE_REQUIREMENTS:-true}"
export E2E_POSTGRES_VERSION="${E2E_POSTGRES_VERSION:-16.8}"
export E2E_POSTGRES_BABELFISH_VERSION="${E2E_POSTGRES_BABELFISH_VERSION:-16.4}"

create_or_replace_cluster_without_defaults() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local INSTANCES="$3"
  shift 3

  create_or_replace_cluster_only "$RELEASE" "$NAMESPACE" "$INSTANCES" \
    "$@"
}

create_or_replace_cluster() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local INSTANCES="$3"
  shift 3

  create_or_replace_cluster_only "$RELEASE" "$NAMESPACE" "$INSTANCES" \
    -f "$SPEC_VALUES_FILE" \
    --set-string cluster.postgres.version="$E2E_POSTGRES_VERSION" \
    $(
    if ! printf %s " $* " | tr -s '\n' ' ' | grep -qF ' --set credentials=null '
    then
      printf '%s %s' --set-string credentials.users.superuser.username="${E2E_SUPERUSER_USERNAME:-postgres}"
    fi
    ) \
    "$@"
}

create_or_replace_cluster_only() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local INSTANCES="$3"
  shift 3

  local OPERATOR_VERSION
  OPERATOR_VERSION="$(get_installed_operator_version)"
  if [ -n "$OPERATOR_VERSION" ] && [ "$OPERATOR_VERSION" != "$STACKGRES_VERSION" ]
  then
    create_or_replace_cluster_for_version_only "$OPERATOR_VERSION" "$RELEASE" "$NAMESPACE" "$INSTANCES" "$@"
    return
  fi

  if helm get values "$RELEASE" --namespace "$NAMESPACE" > /dev/null 2>&1
  then
    helm upgrade "$RELEASE" --namespace "$NAMESPACE" "$CLUSTER_CHART_PATH" \
      --reuse-values \
      $E2E_CLUSTER_PARAMETERS \
      --set nonProductionOptions.disablePatroniResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      --set nonProductionOptions.disableClusterResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      $([ -z "$STACKGRES_TARGET_VERSION" ] || printf '%s' "--set-string cluster.version=$STACKGRES_TARGET_VERSION ") \
      --set cluster.instances="$INSTANCES" "$@"
  else
    create_namespace_if_not_exists "$NAMESPACE"
    helm install "$RELEASE" "$CLUSTER_CHART_PATH" \
      --namespace "$NAMESPACE" \
      $E2E_CLUSTER_PARAMETERS \
      --set nonProductionOptions.disablePatroniResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      --set nonProductionOptions.disableClusterResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      $([ -z "$STACKGRES_TARGET_VERSION" ] || printf '%s' "--set-string cluster.version=$STACKGRES_TARGET_VERSION ") \
      --set cluster.instances="$INSTANCES" "$@"
  fi

  if ! kubectl get sgcluster -n "$NAMESPACE" "$RELEASE" --template '{{ .spec.pods.disableEnvoy }}' | grep -qxF true
  then
    POSTGRES_PORT=7432
    POSTGRES_REPLICATION_PORT=7433
  else
    POSTGRES_PORT=5432
    POSTGRES_REPLICATION_PORT=5432
  fi
}

wait_cluster() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local LEADER

  echo "Wait release $RELEASE"
  wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$RELEASE" \
    --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
    | wc -l)" -ge 1 ]'


  if [ "$WAIT_CLUSTER_AUTHENTICATOR_ONLY" = true ]
  then
    wait_until eval 'kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
        psql -t -A -c "\du" \
        | grep -q "^authenticator|"'
  elif [ "$WAIT_CLUSTER_BOOTSTRAP_ONLY" = true ]
  then
    wait_until kubectl wait -n "$NAMESPACE" "sgcluster/$RELEASE" --for=condition=Bootstrapped --timeout=0s
  else
    wait_until kubectl wait -n "$NAMESPACE" "sgcluster/$RELEASE" --for=condition=InitialScriptsApplied --timeout=0s
  fi
}

switch_cluster_to_first() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local LEADER

  wait_until eval 'kubectl get endpoints --namespace "$NAMESPACE" "$RELEASE" \
    --template="{{ .metadata.annotations.leader }}" | grep -q "^$RELEASE-[0-9]\+"'
  LEADER="$(kubectl get endpoints --namespace "$NAMESPACE" "$RELEASE" \
    --template="{{ .metadata.annotations.leader }}")"
  if [ "$LEADER" != "$RELEASE-0" ]
  then
    wait_until eval '[ "$(kubectl get pod -n "$NAMESPACE" "$RELEASE-0" \
      --template="{{ .metadata.labels.role }}" 2>/dev/null)" = replica ]'
    PATRONI_MAJOR_VERSION="$(kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
      patronictl version 2>/dev/null | sed -n 's/^patronictl version \([0-9]\+\)\..*$/\1/p')"
    wait_until eval '! kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
      patronictl switchover "$RELEASE" \
      $([ "$PATRONI_MAJOR_VERSION" -lt 4 ] && printf %s --master || printf %s --primary) "$LEADER" \
      --candidate "$RELEASE-0" --force \
      | grep -q "^Switchover failed"'
    wait_until eval '[ "$(kubectl get pod -n "$NAMESPACE" "$LEADER" \
      --template="{{ .metadata.labels.role }}" 2>/dev/null)" = replica ]'
    wait_until eval 'kubectl get endpoints --namespace "$NAMESPACE" "$RELEASE" \
      --template="{{ .metadata.annotations.leader }}" | grep -q "^$RELEASE-[0-9]\+"'
  fi
}

wait_cluster_external_dcs() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local SCOPE="$3"
  local SWITCHOVER_TO_FIRST="${4:-true}"
  local LEADER

  echo "Wait release $RELEASE with scope $SCOPE"
  wait_until eval 'kubectl exec --namespace "$NAMESPACE" "$RELEASE-0" -c patroni \
    -- sh -c "patronictl list -f json 2>/dev/null" \
      | jq -r ".[]|select(.Role == \"Leader\").Member" \
      | grep -q .'
  LEADER="$(kubectl exec --namespace "$NAMESPACE" "$RELEASE-0" -c patroni \
    -- sh -c 'patronictl list -f json 2>/dev/null' \
      | jq -r '.[]|select(.Role == "Leader").Member')"

  if [ "${LEADER%-*}" = "$RELEASE" ]
  then
    wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$SCOPE" \
      --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
      | wc -l)" -ge 1 ]'
  fi

  if [ "$LEADER" != "$RELEASE-0" ]
  then
    wait_until eval '[ "$(kubectl get pod -n "$NAMESPACE" "$RELEASE-0" \
      --template="{{ .metadata.labels.role }}" 2>/dev/null)" = replica ]'
  fi

  if [ "$SWITCHOVER_TO_FIRST" = true ] && [ "$LEADER" != "$RELEASE-0" ]
  then
    PATRONI_MAJOR_VERSION="$(kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
      patronictl version 2>/dev/null | sed -n 's/^patronictl version \([0-9]\+\)\..*$/\1/p')"
    wait_until eval '! kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
      patronictl switchover "$SCOPE" \
      $([ "$PATRONI_MAJOR_VERSION" -lt 4 ] && printf %s --master || printf %s --primary) "$LEADER" \
      --candidate "$RELEASE-0" --force \
      | grep -q "^Switchover failed"'
    if [ "${LEADER%-*}" = "$RELEASE" ]
    then
      wait_until eval '[ "$(kubectl get pod -n "$NAMESPACE" "$LEADER" \
        --template="{{ .metadata.labels.role }}" 2>/dev/null)" = replica ]'
      wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$SCOPE" \
        --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
        | wc -l)" -ge 1 ]'
    fi
  fi

  wait_until eval 'kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
      psql -t -A -c "\du" \
      | grep -q "^authenticator|"'
}

has_cluster_generated_resources() {
  kubectl get sts -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" > /dev/null 2>&1
}

create_or_replace_cluster_for_version() {
  local VERSION="$1"
  local RELEASE="$2"
  local NAMESPACE="$3"
  local INSTANCES="$4"
  shift 4

  create_or_replace_cluster_for_version_only "$VERSION" "$RELEASE" "$NAMESPACE" "$INSTANCES" -f "$SPEC_VALUES_FILE" \
    "$@"
}

create_or_replace_cluster_for_version_only() {
  local VERSION="$1"
  local RELEASE="$2"
  local NAMESPACE="$3"
  local INSTANCES="$4"
  shift 4

  if ! [ -d "$LOG_PATH/stackgres-cluster-$VERSION" ]
  then
    mkdir -p "$LOG_PATH/stackgres-cluster-$VERSION"
  fi
  local CLUSTER_HELM_URL
  CLUSTER_HELM_URL="$(get_cluster_helm_url "$VERSION")"
  local CLUSTER_HELM_TAR_PATH="$LOG_PATH/stackgres-cluster-$VERSION/${CLUSTER_HELM_URL##*/}"
  if ! [ -f "$CLUSTER_HELM_TAR_PATH" ]
  then
    curl -f -s -L "$CLUSTER_HELM_URL" -o "$CLUSTER_HELM_TAR_PATH"
  fi
  local CLUSTER_HELM_PATH
  tar tzvf "$CLUSTER_HELM_TAR_PATH" > "$CLUSTER_HELM_TAR_PATH.log"
  CLUSTER_HELM_PATH="$(tr -s ' ' < "$CLUSTER_HELM_TAR_PATH.log" \
    | cut -d ' ' -f 6 | cut -d / -f 1 | head -n 1)"
  CLUSTER_HELM_PATH="$LOG_PATH/stackgres-cluster-$VERSION/$CLUSTER_HELM_PATH"
  if ! [ -f "$CLUSTER_HELM_PATH/Chart.yaml" ]
  then
    rm -rf "$CLUSTER_HELM_PATH"
    tar xzf "$CLUSTER_HELM_TAR_PATH" -C "$LOG_PATH/stackgres-cluster-$VERSION"
    if ! sed -i '/^kubeVersion:/d' "$CLUSTER_HELM_PATH/Chart.yaml"
    then
      rm -rf "$CLUSTER_HELM_PATH"
      return 1
    fi
  fi

  local TRANSFORMER="dont_transform"
  local VERSION_AS_NUMBER VERSION_1_0_0_ALPHA1_AS_NUMBER VERSION_1_2_0_RC1_AS_NUMBER
  VERSION_AS_NUMBER="$(get_version_as_number "$VERSION")"
  VERSION_1_0_0_ALPHA1_AS_NUMBER="$(get_version_as_number 1.0.0-alpha1)"
  VERSION_1_2_0_RC1_AS_NUMBER="$(get_version_as_number 1.2.0-RC1)"
  VERSION_1_3_0_AS_NUMBER="$(get_version_as_number 1.3.0)"
  if [ "$VERSION_AS_NUMBER" -lt "$VERSION_1_0_0_ALPHA1_AS_NUMBER" ]
  then
    TRANSFORMER="transform_to_0_9"
  elif [ "$VERSION_AS_NUMBER" -lt "$VERSION_1_2_0_RC1_AS_NUMBER" ]
  then
    TRANSFORMER="transform_to_1_1"
  elif [ "$VERSION_AS_NUMBER" -lt "$VERSION_1_3_0_AS_NUMBER" ]
  then
    TRANSFORMER="transform_to_1_2"
  fi

  if helm get values "$RELEASE" --namespace "$NAMESPACE" > /dev/null 2>&1
  then
    eval "$(transform_params "$TRANSFORMER" helm upgrade "$RELEASE" --namespace "$NAMESPACE" "$CLUSTER_HELM_PATH" \
        --reuse-values \
        $E2E_CLUSTER_PARAMETERS \
        --set cluster.instances="$INSTANCES" "$@")"
  else
    create_namespace_if_not_exists "$NAMESPACE"
    eval "$(transform_params "$TRANSFORMER" helm install "$RELEASE" "$CLUSTER_HELM_PATH" \
        --namespace "$NAMESPACE" \
        $E2E_CLUSTER_PARAMETERS \
        --set nonProductionOptions.disablePatroniResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
        --set nonProductionOptions.disableClusterResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
        --set cluster.instances="$INSTANCES" "$@")"
  fi

  if ! kubectl get sgcluster -n "$NAMESPACE" "$RELEASE" --template '{{ .spec.pods.disableEnvoy }}' | grep -qxF true
  then
    POSTGRES_PORT=7432
    POSTGRES_REPLICATION_PORT=7433
  else
    POSTGRES_PORT=5432
    POSTGRES_REPLICATION_PORT=5432
  fi
}

create_or_replace_sharded_cluster() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local CLUSTERS="$3"
  local INSTANCES="$4"
  shift 4

  create_or_replace_sharded_cluster_only "$RELEASE" "$NAMESPACE" "$CLUSTERS" "$INSTANCES" \
    -f "$SPEC_VALUES_FILE" \
    --set-string cluster.postgres.version="$E2E_POSTGRES_VERSION" \
    $(
    if ! printf %s " $* " | tr -s '\n' ' ' | grep -qF ' --set cluster.configurations.credentials=null '
    then
      printf '%s %s' --set-string cluster.configurations.credentials.users.superuser.username="${E2E_SUPERUSER_USERNAME:-postgres}"
    fi
    ) \
    "$@"
}

create_or_replace_sharded_cluster_only() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local CLUSTERS="$3"
  local INSTANCES="$4"
  shift 4

  local OPERATOR_VERSION
  OPERATOR_VERSION="$(get_installed_operator_version)"
  if [ -n "$OPERATOR_VERSION" ] && [ "$OPERATOR_VERSION" != "$STACKGRES_VERSION" ]
  then
    create_or_replace_sharded_cluster_for_version_only "$OPERATOR_VERSION" "$RELEASE" "$NAMESPACE" "$CLUSTERS" "$INSTANCES" "$@"
    return
  fi

  if helm get values "$RELEASE" --namespace "$NAMESPACE" > /dev/null 2>&1
  then
    helm upgrade "$RELEASE" --namespace "$NAMESPACE" "$CLUSTER_CHART_PATH" \
      --reuse-values \
      $E2E_CLUSTER_PARAMETERS \
      --set nonProductionOptions.disablePatroniResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      --set nonProductionOptions.disableClusterResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      $([ -z "$STACKGRES_TARGET_VERSION" ] || printf '%s' "--set-string cluster.version=$STACKGRES_TARGET_VERSION ") \
      --set-string kind=SGShardedCluster --set shardedCluster.shards.clusters="$((CLUSTERS - 1))" \
      --set shardedCluster.shards.instancesPerCluster="$INSTANCES" --set cluster.instances="$INSTANCES" "$@"
  else
    create_namespace_if_not_exists "$NAMESPACE"
    helm install "$RELEASE" "$CLUSTER_CHART_PATH" \
      --namespace "$NAMESPACE" \
      $E2E_CLUSTER_PARAMETERS \
      --set nonProductionOptions.disablePatroniResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      --set nonProductionOptions.disableClusterResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
      $([ -z "$STACKGRES_TARGET_VERSION" ] || printf '%s' "--set-string cluster.version=$STACKGRES_TARGET_VERSION ") \
      --set-string kind=SGShardedCluster --set shardedCluster.shards.clusters="$((CLUSTERS - 1))" \
      --set shardedCluster.shards.instancesPerCluster="$INSTANCES" --set cluster.instances="$INSTANCES" "$@"
  fi

  if ! kubectl get sgshardedcluster -n "$NAMESPACE" "$RELEASE" --template '{{ .spec.coordinator.pods.disableEnvoy }}' | grep -qxF true
  then
    POSTGRES_PORT=7432
    POSTGRES_REPLICATION_PORT=7433
  else
    POSTGRES_PORT=5432
    POSTGRES_REPLICATION_PORT=5432
  fi
}

wait_sharded_cluster() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local LEADER

  echo "Wait release $RELEASE"
  wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$RELEASE" \
    --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
    | wc -l)" -ge 1 ]'

  local SHARDED_RELEASE="$RELEASE"
  local INDEX=0
  local ENDPOINTS
  local CLUSTER_SCOPE
  local PATRONICTL_OPTS=""
  local SHARDING_TYPE
  SHARDING_TYPE="$(kubectl get sgshardedcluster -n "$NAMESPACE" "$SHARDED_RELEASE" --template '{{ .spec.type }}')"
  for RELEASE in \
    $(
    if [ "$SHARDING_TYPE" != shardingsphere ]
    then
      printf '%s-coord' "$SHARDED_RELEASE"
    fi) \
    $(
      seq 0 "$(( -1 + $(kubectl get sgshardedcluster -n "$NAMESPACE" "$SHARDED_RELEASE" --template '{{ .spec.shards.clusters }}') ))" \
        | while read INDEX
          do
            printf '%s-shard%s ' "$SHARDED_RELEASE" "$INDEX"
          done)
  do
    RELEASE="$RELEASE"
    if [ "$SHARDING_TYPE" = citus ]
    then
      PATRONICTL_OPTS="--group $INDEX"
      CLUSTER_SCOPE="$SHARDED_RELEASE"
      ENDPOINTS="$SHARDED_RELEASE-$INDEX"
    else
      CLUSTER_SCOPE="$RELEASE"
      ENDPOINTS="$RELEASE"
    fi
    wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$ENDPOINTS" \
      --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
      | wc -l)" -ge 1 ]'

    wait_until eval 'kubectl get endpoints --namespace "$NAMESPACE" "$ENDPOINTS" \
      --template="{{ .metadata.annotations.leader }}" | grep -q "^$RELEASE-[0-9]\+"'

    wait_until eval 'kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
        psql -t -A -c "\du" \
        | grep -q "^authenticator|"'

    INDEX="$((INDEX + 1))"
  done
}

switch_sharded_cluster_to_first() {
  local RELEASE="$1"
  local NAMESPACE="$2"
  local LEADER

  wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$RELEASE" \
    --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
    | wc -l)" -ge 1 ]'

  local SHARDED_RELEASE="$RELEASE"
  local INDEX=0
  local ENDPOINTS
  local CLUSTER_SCOPE
  local PATRONICTL_OPTS=""
  local SHARDING_TYPE
  SHARDING_TYPE="$(kubectl get sgshardedcluster -n "$NAMESPACE" "$SHARDED_RELEASE" --template '{{ .spec.type }}')"
  for RELEASE in \
    $(
    if [ "$SHARDING_TYPE" != shardingsphere ]
    then
      printf '%s-coord' "$SHARDED_RELEASE"
    fi) \
    $(
      seq 0 "$(( -1 + $(kubectl get sgshardedcluster -n "$NAMESPACE" "$SHARDED_RELEASE" --template '{{ .spec.shards.clusters }}') ))" \
        | while read INDEX
          do
            printf '%s-shard%s ' "$SHARDED_RELEASE" "$INDEX"
          done)
  do
    RELEASE="$RELEASE"
    if [ "$SHARDING_TYPE" = citus ]
    then
      PATRONICTL_OPTS="--group $INDEX"
      CLUSTER_SCOPE="$SHARDED_RELEASE"
      ENDPOINTS="$SHARDED_RELEASE-$INDEX"
    else
      CLUSTER_SCOPE="$RELEASE"
      ENDPOINTS="$RELEASE"
    fi
    wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$ENDPOINTS" \
      --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
      | wc -l)" -ge 1 ]'

    wait_until eval 'kubectl get endpoints --namespace "$NAMESPACE" "$ENDPOINTS" \
      --template="{{ .metadata.annotations.leader }}" | grep -q "^$RELEASE-[0-9]\+"'
    LEADER="$(kubectl get endpoints --namespace "$NAMESPACE" "$ENDPOINTS" \
      --template="{{ .metadata.annotations.leader }}")"
    if [ "$LEADER" != "$RELEASE-0" ]
    then
      wait_until eval '[ "$(kubectl get pod -n "$NAMESPACE" "$RELEASE-0" \
        --template="{{ .metadata.labels.role }}" 2>/dev/null)" = replica ]'
      PATRONI_MAJOR_VERSION="$(kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
        patronictl version 2>/dev/null | sed -n 's/^patronictl version \([0-9]\+\)\..*$/\1/p')"
      wait_until eval '! kubectl exec -n "$NAMESPACE" "$RELEASE-0" -c patroni -- \
        patronictl switchover "$CLUSTER_SCOPE" $PATRONICTL_OPTS \
        $([ "$PATRONI_MAJOR_VERSION" -lt 4 ] && printf %s --master || printf %s --primary) "$LEADER" \
        --candidate "$RELEASE-0" --force \
        | grep -q "^Switchover failed"'
      wait_until eval '[ "$(kubectl get pod -n "$NAMESPACE" "$LEADER" \
        --template="{{ .metadata.labels.role }}" 2>/dev/null)" = replica ]'
      wait_until eval '[ "$(kubectl get endpoints --namespace "$NAMESPACE" "$ENDPOINTS" \
        --template="{{ range .subsets }}{{ range .addresses }}{{ printf \"%s\n\" .ip }}{{ end }}{{ end }}" 2>/dev/null \
        | wc -l)" -ge 1 ]'
    fi

    INDEX="$((INDEX + 1))"
  done
}

create_or_replace_sharded_cluster_for_version() {
  local VERSION="$1"
  local RELEASE="$2"
  local NAMESPACE="$3"
  local CLUSTERS="$4"
  local INSTANCES="$5"
  shift 5

  create_or_replace_sharded_cluster_for_version_only "$VERSION" "$RELEASE" "$NAMESPACE" "$CLUSTERS" "$INSTANCES" -f "$SPEC_VALUES_FILE" \
    "$@"
}

create_or_replace_sharded_cluster_for_version_only() {
  local VERSION="$1"
  local RELEASE="$2"
  local NAMESPACE="$3"
  local CLUSTERS="$4"
  local INSTANCES="$5"
  shift 5

  if ! [ -d "$LOG_PATH/stackgres-cluster-$VERSION" ]
  then
    mkdir -p "$LOG_PATH/stackgres-cluster-$VERSION"
  fi
  local CLUSTER_HELM_URL
  CLUSTER_HELM_URL="$(get_cluster_helm_url "$VERSION")"
  local CLUSTER_HELM_TAR_PATH="$LOG_PATH/stackgres-cluster-$VERSION/${CLUSTER_HELM_URL##*/}"
  if ! [ -f "$CLUSTER_HELM_TAR_PATH" ]
  then
    curl -f -s -L "$CLUSTER_HELM_URL" -o "$CLUSTER_HELM_TAR_PATH"
  fi
  local CLUSTER_HELM_PATH
  tar tzvf "$CLUSTER_HELM_TAR_PATH" > "$CLUSTER_HELM_TAR_PATH.log"
  CLUSTER_HELM_PATH="$(tr -s ' ' < "$CLUSTER_HELM_TAR_PATH.log" \
    | cut -d ' ' -f 6 | cut -d / -f 1 | head -n 1)"
  CLUSTER_HELM_PATH="$LOG_PATH/stackgres-cluster-$VERSION/$CLUSTER_HELM_PATH"
  if ! [ -f "$CLUSTER_HELM_PATH/Chart.yaml" ]
  then
    rm -rf "$CLUSTER_HELM_PATH"
    tar xzf "$CLUSTER_HELM_TAR_PATH" -C "$LOG_PATH/stackgres-cluster-$VERSION"
    if ! sed -i '/^kubeVersion:/d' "$CLUSTER_HELM_PATH/Chart.yaml"
    then
      rm -rf "$CLUSTER_HELM_PATH"
      return 1
    fi
  fi

  local TRANSFORMER="dont_transform"
  local VERSION_AS_NUMBER VERSION_1_0_0_ALPHA1_AS_NUMBER VERSION_1_2_0_RC1_AS_NUMBER
  VERSION_AS_NUMBER="$(get_version_as_number "$VERSION")"
  VERSION_1_0_0_ALPHA1_AS_NUMBER="$(get_version_as_number 1.0.0-alpha1)"
  VERSION_1_2_0_RC1_AS_NUMBER="$(get_version_as_number 1.2.0-RC1)"
  VERSION_1_3_0_AS_NUMBER="$(get_version_as_number 1.3.0)"
  if [ "$VERSION_AS_NUMBER" -lt "$VERSION_1_0_0_ALPHA1_AS_NUMBER" ]
  then
    TRANSFORMER="transform_to_0_9"
  elif [ "$VERSION_AS_NUMBER" -lt "$VERSION_1_2_0_RC1_AS_NUMBER" ]
  then
    TRANSFORMER="transform_to_1_1"
  elif [ "$VERSION_AS_NUMBER" -lt "$VERSION_1_3_0_AS_NUMBER" ]
  then
    TRANSFORMER="transform_to_1_2"
  fi

  if helm get values "$RELEASE" --namespace "$NAMESPACE" > /dev/null 2>&1
  then
    eval "$(transform_params "$TRANSFORMER" helm upgrade "$RELEASE" --namespace "$NAMESPACE" "$CLUSTER_HELM_PATH" \
        --reuse-values \
        $E2E_CLUSTER_PARAMETERS \
        --set-string kind=SGShardedCluster --set shardedCluster.shards.clusters="$((CLUSTERS - 1))" \
        --set shardedCluster.shards.instancesPerCluster="$INSTANCES" --set cluster.instances="$INSTANCES" "$@")"
  else
    create_namespace_if_not_exists "$NAMESPACE"
    eval "$(transform_params "$TRANSFORMER" helm install "$RELEASE" "$CLUSTER_HELM_PATH" \
        --namespace "$NAMESPACE" \
        $E2E_CLUSTER_PARAMETERS \
        --set nonProductionOptions.disablePatroniResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
        --set nonProductionOptions.disableClusterResourceRequirements="$E2E_DISABLE_RESOURCE_REQUIREMENTS" \
        --set-string kind=SGShardedCluster --set shardedCluster.shards.clusters="$((CLUSTERS - 1))" \
        --set shardedCluster.shards.instancesPerCluster="$INSTANCES" --set cluster.instances="$INSTANCES" "$@")"
  fi
}

transform_to_1_2() {
  if printf '%s' "$1" | grep -q '^cluster\.managedSql\.scripts'
  then
    printf '%s' "$1" | sed 's/^cluster\.managedSql\.scripts/cluster.initialData.scripts/'
  elif [ "${1%=*}" = 'cluster.configurations.backups.sgObjectStorage' ]
  then
    printf "%s=%s" "cluster.configurations.sgBackupConfig" "${1#*=}"
  elif [ "${1%=*}" = 'configurations.objectstorage.create' ]
  then
    printf "%s=%s" "configurations.backupconfig.create" "${1#*=}"
  elif printf '%s' "$1" | grep -q '^configurations\.objectstorage\.'
  then
    printf '%s' "$1" | sed 's/^configurations\.objectstorage\./configurations.backupconfig.storage./'
  elif printf '%s' "$1" | grep -q '^cluster\.configurations\.backups\.'
  then
    printf '%s' "$1" | sed 's/^cluster\.configurations\.backups\./configurations.backupconfig.baseBackups./'
  else
    dont_transform "$1"
  fi
}

transform_to_1_1() {
  if printf '%s' "$1" | grep -q '^cluster\.managedSql\.scripts'
  then
    printf '%s' "$1" | sed 's/^cluster\.managedSql\.scripts/cluster.initialData.scripts/'
  elif [ "${1%=*}" = 'configurations.backupconfig.baseBackups.performance.maxDiskBandwidth' ]
  then
    printf "%s=%s" "configurations.backupconfig.baseBackups.performance.maxDiskBandwitdh" "${1#*=}"
  elif [ "${1%=*}" = 'configurations.backupconfig.baseBackups.performance.maxNetworkBandwidth' ]
  then
    printf "%s=%s" "configurations.backupconfig.baseBackups.performance.maxNetworkBandwitdh" "${1#*=}"
  elif [ "${1%=*}" = "cluster.initialData.restore.fromBackup.name" ]
  then
    local BACKUP_UID
    BACKUP_UID="$(kubectl get sgbackup -n "$NAMESPACE" "${1#*=}" --template '{{ .metadata.uid }}')"
    printf "%s=%s" "cluster.initialData.restore.fromBackup.uid" "$BACKUP_UID"
  else
    transform_to_1_2 "$1"
  fi
}

transform_to_0_9() {
  if printf '%s' "$1" | grep -q '^cluster\.metadata\.labels\.clusterPods\.'
  then
    printf '%s' "$1" | sed 's/^cluster\.metadata\.labels\.clusterPods\./cluster.pods.metadata.labels./'
  elif printf '%s' "$1" | grep -q '^cluster\.metadata\.annotations\.clusterPods\.'
  then
    printf '%s' "$1" | sed 's/^cluster\.metadata\.annotations\.clusterPods\./cluster.metadata.annotations.pods./'
  elif printf '%s' "$1" | grep -q '^cluster\.metadata\.annotations\.primaryService\.'
  then
    printf '%s' "$1" | sed 's/^cluster\.metadata\.annotations\.primaryService\./cluster.postgresServices.primary.annotations./'
  elif printf '%s' "$1" | grep -q '^cluster\.metadata\.annotations\.replicasService\.'
  then
    printf '%s' "$1" | sed 's/^cluster\.metadata\.annotations\.replicasService\./cluster.postgresServices.replicas.annotations./'
  elif [ "${1%=*}" = 'cluster.postgres.version' ]
  then
    printf '%s=%s' 'cluster.postgresVersion' "${1#*=}"
  elif printf '%s' '${1%=*}' | grep -q '^cluster.postgres.extensions'
  then
    printf "%s=%s" "$(printf '%s' "${1%=*}" \
      | sed 's/^cluster\.postgres\.extensions/cluster.postgresExtensions/')" "${1#*=}"
  elif [ "${1%=*}" = "cluster.initialData.restore.fromBackup.uid" ]
  then
    printf "%s=%s" "cluster.initialData.restore.fromBackup" "${1#*=}"
  else
    transform_to_1_1 "$1"
  fi
}

dont_transform() {
  printf "%s" "$1"
}

remove_cluster() {
  local RELEASE="$1"
  local NAMESPACE="$2"

  echo "Deleting release $RELEASE" 
  helm get manifest "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null \
    | yq 'select(.kind == "SGCluster")' \
    | kubectl delete --namespace "$NAMESPACE" --ignore-not-found -f -
  helm get manifest "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null \
    | kubectl delete --namespace "$NAMESPACE" --ignore-not-found -f -
  helm get hooks "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null \
    | kubectl delete --namespace "$NAMESPACE" --ignore-not-found -f -
  helm uninstall "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null || true
}

remove_cluster_if_exists() {
  local RELEASE="$1"
  local NAMESPACE="$2"

  if helm get values "$RELEASE"  --namespace "$NAMESPACE" > /dev/null 2>&1
  then
    remove_cluster "$RELEASE" "$NAMESPACE"
  fi
}

remove_sharded_cluster() {
  local RELEASE="$1"
  local NAMESPACE="$2"

  echo "Deleting release $RELEASE" 
  helm get manifest "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null \
    | yq 'select(.kind == "SGShardedCluster")' \
    | kubectl delete --namespace "$NAMESPACE" --ignore-not-found --wait=true -f -
  helm get manifest "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null \
    | kubectl delete --namespace "$NAMESPACE" --ignore-not-found -f -
  wait_until eval 'helm get hooks "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null \
    | kubectl delete --namespace "$NAMESPACE" --ignore-not-found -f -'
  helm uninstall "$RELEASE" --namespace "$NAMESPACE" 2>/dev/null || true
}

remove_sharded_cluster_if_exists() {
  local RELEASE="$1"
  local NAMESPACE="$2"

  if helm get values "$RELEASE"  --namespace "$NAMESPACE" > /dev/null 2>&1
  then
    remove_sharded_cluster "$RELEASE" "$NAMESPACE"
  fi
}
